home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / basics / qtmovietrack / common files / winframework.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  29.7 KB  |  993 lines

  1. //////////
  2. //
  3. //    File:        WinFramework.c
  4. //
  5. //    Contains:    Code for the QuickTime sample code framework that is specific to Windows. 
  6. //                This code handles windows, menus, events, and other low-level things. Put your
  7. //                application-specific code into the file ComApplication.c. 
  8. //
  9. //    Written by:    Tim Monroe
  10. //                Based on the QTShell code written by Tim Monroe, which in turn was based on the MDIPlayer
  11. //                code written by Brian S. Friedkin (Aug 5, 1996). This current version is now very far removed from
  12. //                MDIPlayer.
  13. //
  14. //    Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  15. //
  16. //    Change History (most recent first):
  17. //
  18. //       <7>         04/03/00    rtm        reworked QTFrame_CalcWindowMinMaxInfo; disabled movie window maximize button
  19. //                                    in WM_CREATE message processing (implementing this is left as an exercise...)
  20. //       <6>         01/14/00    rtm        reworked window-drawing code (WM_PAINT message) to support graphics files
  21. //       <5>         01/05/00    rtm        minor tweaks to QuickTime initialization in WinMain
  22. //       <4>         12/26/99    rtm        added WM_LBUTTONDOWN processing to QTFrame_MovieWndProc; minor reorganization
  23. //                                    of QTFrame_MovieWndProc so that myMacEvent and myIsHandled are in scope for
  24. //                                    that message
  25. //       <3>         12/16/99    rtm        made minor change to QTFrame_MovieWndProc so that QTApp_HandleEvent is called
  26. //                                    even if the window has no movie controller
  27. //       <2>         11/29/99    rtm        modified "Save changes" dialog box to use Macintosh wordings prompted by move
  28. //                                    to Navigation Services
  29. //       <1>         11/05/99    rtm        first file; based on earlier sample code
  30. //       
  31. //////////
  32.  
  33. //////////
  34. //
  35. // header files
  36. //
  37. //////////
  38.  
  39. #include "WinFramework.h"
  40.  
  41.  
  42. //////////
  43. //
  44. // global variables
  45. //
  46. //////////
  47.  
  48. BOOL                gShuttingDown = false;                // are we shutting down?
  49. BOOL                gWeAreSizingWindow = false;            // are we resizing a window?
  50. BOOL                gWeAreCreatingWindow = false;        // are we creating a window?
  51.  
  52. HANDLE                ghInst;                                // the instance of this application
  53. HWND                ghWnd;                                // the MDI frame window; this window has the menu bar
  54. HWND                ghWndMDIClient;                     // the MDI client window
  55.  
  56. char                gChildName[] = "QTShellChild";
  57. char                gMovieType[] = "QuickTime Movie";
  58.  
  59. short                 gAppResFile = kInvalidFileRefNum;    // file reference number for this application's resource file
  60. FSSpec                gAppFSSpec;                            // file specification for the application itself
  61. char                gAppName[20];                        // the name of this application
  62.  
  63. LPSTR                gCmdLine;                            // the command line passed to WinMain
  64.  
  65. extern Rect            gMCResizeBounds;                    // maximum size for any movie window
  66.  
  67. ModalFilterUPP        gModalFilterUPP = NULL;                // UPP to our custom dialog event filter
  68.  
  69.  
  70. //////////
  71. //
  72. // WinMain
  73. // The main function for this application.
  74. //
  75. // Set up the application's execution environment; make sure QuickTime (etc.) is installed,
  76. // then start handling events. If we terminate before reaching the message loop, we should
  77. // return 0.
  78. //
  79. //////////
  80.  
  81. int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR theCmdLine, int nCmdShow)
  82. {
  83.     HANDLE                myAccel;
  84.     HWND                myWindowFrame;
  85.     MSG                    myMsg;
  86.     WNDCLASSEX            myWC;
  87.     char                myFileName[MAX_PATH];
  88.     DWORD                myLength;
  89.     OSErr                myErr = noErr;
  90.  
  91.     ghInst = hInstance;
  92.     gCmdLine = theCmdLine;
  93.     
  94.     if (hPrevInstance == NULL) {
  95.         LoadString(hInstance, IDS_APPNAME, gAppName, sizeof(gAppName));
  96.         
  97.         // register the frame window class
  98.         myWC.cbSize        = sizeof(WNDCLASSEX);
  99.         myWC.style         = CS_HREDRAW | CS_VREDRAW;
  100.         myWC.lpfnWndProc   = (WNDPROC)QTFrame_FrameWndProc;
  101.         myWC.cbClsExtra    = 0;
  102.         myWC.cbWndExtra    = 0;
  103.         myWC.hInstance     = hInstance;
  104.         myWC.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
  105.         myWC.hCursor       = LoadCursor(NULL, IDC_ARROW);
  106.         myWC.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  107.         myWC.lpszMenuName  = gAppName;
  108.         myWC.lpszClassName = gAppName;
  109.         myWC.hIconSm       = LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, 0);
  110.                                      
  111.         if (!RegisterClassEx(&myWC)) {
  112.             if (!RegisterClass((LPWNDCLASS)&myWC.style))
  113.                 return(0);
  114.         }
  115.  
  116.         // register the movie child window class
  117.         myWC.cbSize        = sizeof(WNDCLASSEX);
  118.         myWC.style         = 0;
  119.         myWC.lpfnWndProc   = (WNDPROC)QTFrame_MovieWndProc;
  120.         myWC.cbClsExtra    = 0;
  121.         myWC.cbWndExtra    = 0;
  122.         myWC.hInstance     = hInstance;
  123.         myWC.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CHILDICON));
  124.         // to avoid having QuickTime VR "fight" with the system over the cursor,
  125.         // we set the client area cursor to NULL; this means that for QuickTime
  126.         // movies, we'll need to change the cursor to an arrow manually; see the
  127.         // handling of the WM_MOUSEMOVE message in QTFrame_MovieWndProc
  128.         myWC.hCursor       = NULL;
  129.         myWC.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  130.         myWC.lpszMenuName  = NULL;
  131.         myWC.lpszClassName = gChildName;
  132.         myWC.hIconSm       = LoadImage(hInstance, MAKEINTRESOURCE(IDI_CHILDICON), IMAGE_ICON, 16, 16, 0);
  133.                                      
  134.         if (!RegisterClassEx(&myWC)) {
  135.             if (!RegisterClass((LPWNDCLASS)&myWC.style))
  136.                 return(0);
  137.         }
  138.     }
  139.  
  140.     // load accelerators
  141.     myAccel = LoadAccelerators(hInstance, gAppName);
  142.  
  143.     // initialize QuickTime Media Layer and QuickTime; alert the user and return 0 if unsuccessful
  144.     myErr = InitializeQTML(0L);
  145.     if (myErr != noErr) {
  146.         MessageBox(NULL, "QuickTime is not installed on this computer. Exiting.", gAppName, MB_OK | MB_APPLMODAL);
  147.         return(0);
  148.     }
  149.     
  150.     myErr = EnterMovies();
  151.     if (myErr != noErr) {
  152.         MessageBox(NULL, "Could not initialize QuickTime. Exiting.", gAppName, MB_OK | MB_APPLMODAL);
  153.         return(0);
  154.     }
  155.  
  156.     // get the application's resource file, if it exists
  157.     myLength = GetModuleFileName(NULL, myFileName, MAX_PATH);        // NULL means: the current process
  158.     if (myLength != 0) {
  159.         NativePathNameToFSSpec(myFileName, &gAppFSSpec, kFullNativePath);
  160.  
  161.         gAppResFile = FSpOpenResFile(&gAppFSSpec, fsRdWrPerm);
  162.         if (gAppResFile != kInvalidFileRefNum)
  163.             UseResFile(gAppResFile);
  164.     }
  165.  
  166.     // do any application-specific initialization that must occur before the frame window is created
  167.     QTApp_Init(kInitAppPhase_BeforeCreateFrameWindow);
  168.     
  169.     // create the main frame window
  170.     myWindowFrame = CreateWindow(gAppName, gAppName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  171.                                        CW_USEDEFAULT, 
  172.                                        CW_USEDEFAULT,
  173.                                      CW_USEDEFAULT, 
  174.                                      CW_USEDEFAULT,
  175.                                      NULL, 
  176.                                      NULL, 
  177.                                      hInstance, 
  178.                                      NULL);
  179.     ghWnd = myWindowFrame;
  180.     
  181.     // make sure we got a frame window
  182.     if (myWindowFrame == NULL)
  183.         return(0);
  184.         
  185.     // show the window
  186.     ShowWindow(myWindowFrame, nCmdShow);
  187.     UpdateWindow(myWindowFrame);
  188.     
  189.     // do any application-specific initialization that must occur after the frame window is created
  190.     QTApp_Init(kInitAppPhase_AfterCreateFrameWindow);
  191.     
  192.     // get and process events until the user quits
  193.     while (GetMessage(&myMsg, NULL, 0, 0)) {    
  194.         if (!TranslateMDISysAccel(ghWndMDIClient, &myMsg)) {
  195.             if (!TranslateAccelerator(myWindowFrame, myAccel, &myMsg)) {
  196.                 TranslateMessage(&myMsg);
  197.                 DispatchMessage(&myMsg);
  198.             }
  199.         }
  200.     }
  201.  
  202.     // close the application's resource file, if it was previously opened
  203.     if (gAppResFile != kInvalidFileRefNum)
  204.         CloseResFile(gAppResFile);
  205.  
  206.     // terminate the QuickTime Media Layer
  207.     ExitMovies();
  208.     TerminateQTML();
  209.  
  210.     return(myMsg.wParam);            // returns the value from PostQuitMessage
  211. }
  212.  
  213.  
  214. //////////
  215. //
  216. // QTFrame_FrameWndProc
  217. // The window procedure for the MDI frame window.
  218. //
  219. //////////
  220.  
  221. LRESULT CALLBACK QTFrame_FrameWndProc (HWND theWnd, UINT theMessage, UINT wParam, LONG lParam)
  222. {
  223.     HWND                   myChild;
  224.  
  225.     switch (theMessage) {
  226.     
  227.         case WM_CREATE: {
  228.             CLIENTCREATESTRUCT        myClientStruct = {0};
  229.  
  230.             myClientStruct.hWindowMenu  = GetSubMenu(GetMenu(theWnd), WINDOWMENU);
  231.             myClientStruct.idFirstChild = IDM_WINDOWCHILD;
  232.             
  233.             // create the MDI client filling the client area
  234.             ghWndMDIClient = CreateWindow("mdiclient",
  235.                                          NULL,
  236.                                          WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
  237.                                          0, 0, 0, 0,
  238.                                          theWnd,
  239.                                          (HMENU)0xCAC,
  240.                                          ghInst,
  241.                                          (LPVOID)&myClientStruct);
  242.             
  243.             // set initial menu state
  244.             QTFrame_AdjustMenus(NULL, GetMenu(theWnd));
  245.             
  246.             if (ghWndMDIClient != NULL)
  247.                 ShowWindow(ghWndMDIClient, SW_SHOW);
  248.             
  249.             return(0);
  250.         }
  251.  
  252.         case WM_ACTIVATE:
  253.             // the MDI frame window is being activated or deactivated;
  254.             // activate or deactivate any active child window by sending this message to DefMDIChildProc 
  255.             myChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
  256.             if (IsWindow(myChild))
  257.                 SendMessage(myChild, WM_ACTIVATE, wParam, lParam);
  258.             break;
  259.  
  260.         case WM_COMMAND: {
  261.  
  262.             switch (LOWORD(wParam)) {
  263.                 case IDM_FILENEW:
  264.                 case IDM_FILEOPEN:
  265.                 case IDM_FILECLOSE:
  266.                 case IDM_EXIT:
  267.                     QTFrame_HandleFileMenuItem(NULL, LOWORD(wParam));
  268.                     return(0);
  269.  
  270.                 case IDM_FILESAVE:
  271.                 case IDM_FILESAVEAS:
  272.                     // save the active child window
  273.                     myChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
  274.                     if (IsWindow(myChild))
  275.                         SendMessage(myChild, WM_COMMAND, wParam, lParam);
  276.                     return(0);
  277.  
  278.                 case IDM_WINDOWTILE:
  279.                     SendMessage(ghWndMDIClient, WM_MDITILE, 0, 0L);
  280.                     return(0);
  281.  
  282.                 case IDM_WINDOWCASCADE:
  283.                     SendMessage(ghWndMDIClient, WM_MDICASCADE, 0, 0L);
  284.                     return(0);
  285.  
  286.                 case IDM_WINDOWICONS:
  287.                     SendMessage(ghWndMDIClient, WM_MDIICONARRANGE, 0, 0L);
  288.                     return(0);
  289.  
  290.                 case IDM_WINDOWCLOSEALL: {
  291.                     WindowReference        myWindow, myNextWindow;
  292.             
  293.                     // walk the window list and destroy any open windows
  294.                     myWindow = QTFrame_GetFrontMovieWindow();
  295.                     while (myWindow != NULL) {
  296.                         myNextWindow = QTFrame_GetNextMovieWindow(myWindow);
  297.                         SendMessage(myWindow, WM_CLOSE, 0L, 0L);
  298.                         myWindow = myNextWindow;
  299.                     }
  300.                     
  301.                     return(0);
  302.                 }
  303.  
  304.                 case IDM_ABOUT:
  305.                     QTFrame_ShowAboutBox();
  306.                     return(0);
  307.  
  308.                 default:                
  309.                     // pass this message to the active child window...
  310.                     myChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
  311.                     if (IsWindow(myChild))
  312.                         SendMessage(myChild, WM_COMMAND, wParam, lParam);
  313.  
  314.                     // ...then do any application-specific menu handling, if no movie windows are open...
  315.                     if (myChild == NULL)
  316.                         QTApp_HandleMenu((UInt16)LOWORD(wParam));
  317.                     
  318.                     // ...and then pass it to DefFrameProc
  319.                     break;
  320.             }
  321.             break;
  322.         }
  323.  
  324.         case WM_OPENDROPPEDFILES:
  325.             // open any movie files that were dropped onto the application icon
  326.             QTFrame_OpenCommandLineMovies(gCmdLine);
  327.             return(0);
  328.  
  329.         case WM_INITMENU:
  330.             if (GetMenu(theWnd) == (HMENU)wParam)
  331.                 return(QTFrame_AdjustMenus((HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L), (HMENU)wParam));
  332.             return(1);
  333.  
  334.         case WM_CLOSE:
  335.             // if we're not already in the process of shutting down,
  336.             // simulate the selection of the Quit menu command
  337.             if (!gShuttingDown) {
  338.                 SendMessage(ghWnd, WM_COMMAND, IDM_EXIT, 0L);
  339.                 return(0);
  340.             }
  341.             break;
  342.             
  343.         case WM_DESTROY:
  344.             // do any application-specific shutdown
  345.             QTApp_Stop(kStopAppPhase_AfterDestroyWindows);
  346.             PostQuitMessage(0);
  347.             break;
  348.     }
  349.     
  350.     return(DefFrameProc(theWnd, ghWndMDIClient, theMessage, wParam, lParam));
  351. }
  352.  
  353.  
  354. //////////
  355. //
  356. // QTFrame_MovieWndProc
  357. // The window procedure for a movie window.
  358. //
  359. //////////
  360.  
  361. LRESULT CALLBACK QTFrame_MovieWndProc (HWND theWnd, UINT theMessage, UINT wParam, LONG lParam)
  362. {
  363.     WPARAM                myWidth, myHeight;
  364.     MovieController        myMC = NULL;
  365.     Movie                myMovie = NULL;
  366.     WindowObject        myWindowObject = NULL;
  367.     MSG                    myMsg = {0};
  368.     EventRecord            myMacEvent;
  369.     Boolean                myIsHandled = false;
  370.  
  371.     // get the window object, movie, and movie controller for this window
  372.     myWindowObject = QTFrame_GetWindowObjectFromWindow(theWnd);
  373.     if (myWindowObject != NULL) {
  374.         myMC = (**myWindowObject).fController;
  375.         myMovie = (**myWindowObject).fMovie;
  376.     }
  377.  
  378.     // give the movie controller this message first
  379.     if (!gShuttingDown) {
  380.         LONG            myPoints = GetMessagePos();
  381.  
  382.         myMsg.hwnd = theWnd;
  383.         myMsg.message = theMessage;
  384.         myMsg.wParam = wParam;
  385.         myMsg.lParam = lParam;
  386.         myMsg.time = GetMessageTime();
  387.         myMsg.pt.x = LOWORD(myPoints);
  388.         myMsg.pt.y = HIWORD(myPoints);
  389.  
  390.         // translate a Windows event to a Mac event
  391.         WinEventToMacEvent(&myMsg, &myMacEvent);
  392.  
  393.         // let the application-specific code have a chance to intercept the event
  394.         myIsHandled = QTApp_HandleEvent(&myMacEvent);
  395.         
  396.         // pass the Mac event to the movie controller, but only if the movie window isn't minimized
  397.         if (!myIsHandled)
  398.             if (myMC != NULL)
  399.                 if (!IsIconic(theWnd))
  400.                     myIsHandled = MCIsPlayerEvent(myMC, (EventRecord *)&myMacEvent);
  401.     }
  402.  
  403.     switch (theMessage) {
  404.         case WM_CREATE: {
  405.                 LONG        myStyles;
  406.                 
  407.                 // create a new window object associated with the new window
  408.                 QTFrame_CreateWindowObject(theWnd);
  409.             
  410.                 // disable the maximize button
  411.                 myStyles = GetWindowLong(theWnd, GWL_STYLE);
  412.                 myStyles &= ~WS_MAXIMIZEBOX;
  413.                 SetWindowLong(theWnd, GWL_STYLE, myStyles);
  414.             }
  415.             break;
  416.  
  417.         case WM_WINDOWPOSCHANGING:
  418.             // don't show the window until we have created a movie and
  419.             // can therefore properly size the window to contain the movie
  420.             if (gWeAreCreatingWindow) {
  421.                 WINDOWPOS    *lpWindowPos = (WINDOWPOS*)lParam;
  422.                 
  423.                 lpWindowPos->flags &= ~SWP_SHOWWINDOW;
  424.             }
  425.             break;
  426.  
  427.         case WM_WINDOWPOSCHANGED:
  428.             // if a movie window has become minimized, stop the movie
  429.             if (IsIconic(theWnd))
  430.                 StopMovie(myMovie);
  431.             break;
  432.  
  433.         case WM_SIZE:
  434.             // resize the movie and controller to fit the window
  435.             myWidth = LOWORD(lParam);
  436.             myHeight = HIWORD(lParam);
  437.             
  438.             // we do NOT want to resize the movie controller if the window is minimized,
  439.             // if there is no movie controller, or if we are in the middle of resizing the window
  440.             if (!gWeAreSizingWindow && (myMC != NULL) && (wParam != SIZE_MINIMIZED)) {
  441.                 Rect        myRect;
  442.                 
  443.                 myRect.top = 0;
  444.                 myRect.left = 0;
  445.                 myRect.right = myWidth;
  446.                 myRect.bottom = myHeight;
  447.                 
  448.                 MCSetControllerBoundsRect(myMC, &myRect);
  449.             }
  450.             break;
  451.  
  452.         case WM_MOUSEMOVE:
  453.             // for QuickTime movies (but NOT for QuickTime VR movies), set the cursor to the arrow cursor
  454.             if (myWindowObject != NULL)
  455.                 if (!(**myWindowObject).fIsQTVRMovie)
  456.                     SetCursor(LoadCursor(NULL, IDC_ARROW));
  457.             break;
  458.  
  459.         case WM_PUMPMOVIE:
  460.             // we receive this message only to task the movie
  461.             break;
  462.  
  463.         case WM_LBUTTONDOWN:
  464.             // do any application-specific mouse-button handling, but only if the message hasn't already been handled
  465.             if (!myIsHandled)
  466.                 QTApp_HandleContentClick(theWnd, &myMacEvent);
  467.             break;
  468.  
  469.         case WM_CHAR:
  470.             // do any application-specific key press handling
  471.             QTApp_HandleKeyPress((char)wParam);
  472.             break;
  473.  
  474.         case WM_PAINT: {
  475.             // do any application-specific drawing in the window
  476.                 PAINTSTRUCT        myPaintStruct;
  477.             
  478.                 BeginPaint(theWnd, &myPaintStruct);
  479.  
  480.                 // if the window contains an image, draw it using GraphicsImportDraw
  481.                 if (myWindowObject != NULL)
  482.                     if ((**myWindowObject).fGraphicsImporter != NULL)
  483.                         GraphicsImportDraw((**myWindowObject).fGraphicsImporter);
  484.             
  485.                 QTApp_Draw(theWnd, NULL);
  486.                 EndPaint(theWnd, &myPaintStruct);
  487.             }
  488.             break;
  489.  
  490.         case WM_MDIACTIVATE:
  491.             // activate or deactivate the movie controller in the specified window
  492.             QTFrame_ActivateController(theWnd, (HWND)theWnd == (HWND)lParam);
  493.             break;
  494.  
  495.         case WM_COMMAND: {
  496.  
  497.             switch (LOWORD(wParam)) {
  498.                             
  499.                 case IDM_FILESAVE:
  500.                 case IDM_FILESAVEAS:
  501.                     QTFrame_HandleFileMenuItem(theWnd, LOWORD(wParam));
  502.                     break;
  503.  
  504.                 case IDM_EDITUNDO:
  505.                 case IDM_EDITCUT:
  506.                 case IDM_EDITCOPY:
  507.                 case IDM_EDITPASTE:
  508.                 case IDM_EDITCLEAR:
  509.                 case IDM_EDITSELECTALL:
  510.                 case IDM_EDITSELECTNONE:
  511.                     QTFrame_HandleEditMenuItem(theWnd, LOWORD(wParam));
  512.                     break;
  513.                     
  514.                 default:
  515.                     // do any application-specific menu handling
  516.                     QTApp_HandleMenu((UInt16)LOWORD(wParam));
  517.                     break;
  518.             }
  519.             
  520.             break;
  521.         }    // case WM_COMMAND
  522.  
  523.         case WM_GETMINMAXINFO:
  524.             QTFrame_CalcWindowMinMaxInfo(theWnd, (LPMINMAXINFO)lParam);
  525.             return(0);
  526.  
  527.         case WM_CLOSE:
  528.             // prepare to close the window, making sure that any changed data is saved or explicitly discarded;
  529.             // we can still cancel the window closing here
  530.             if (myWindowObject != NULL) {
  531.             
  532.                 // if the window's data is "dirty", give the user a chance to save it
  533.                 if ((**myWindowObject).fIsDirty) {
  534.                     int            myItem;
  535.                     char        myText[256];
  536.                     UINT        myAction;
  537.         
  538.                     // get the title of the window
  539.                     GetWindowText(theWnd, myText, sizeof(myText));
  540.         
  541.                     // specify the action
  542.                     myAction = gShuttingDown ? IDS_SAVEONQUIT : IDS_SAVEONCLOSE;
  543.         
  544.                     // display the "Save changes" dialog box
  545.                     myItem = QTFrame_ShowCautionAlert(theWnd, myAction, MB_ICONEXCLAMATION, MB_YESNOCANCEL, gAppName, myText);
  546.                     switch (myItem) {
  547.                         case kSaveChanges:
  548.                             // save the data in the window
  549.                             QTFrame_UpdateMovieFile(theWnd);
  550.                             break;
  551.                             
  552.                         case kCancelClose:
  553.                             // do not close the window and do not quit the application
  554.                             gShuttingDown = false;
  555.                             return(0);
  556.                         
  557.                         case kDontSaveChanges:
  558.                             // discard any unsaved changes (that is, don't do anything)
  559.                             break;
  560.                             
  561.                         default:
  562.                             // unexpected item selected; just return
  563.                             return(0);
  564.                     }
  565.                 }
  566.             } // if (myWindowObject != NULL)
  567.             
  568.             // if we got to this point, it's okay to close and destroy the window
  569.             SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)theWnd, 0L);
  570.             break;
  571.  
  572.         case WM_DESTROY:
  573.             // when we get this message,
  574.             // the window has been removed from the screen and its associated data must be destroyed
  575.             if (myWindowObject != NULL)
  576.                 QTFrame_CloseWindowObject(myWindowObject);
  577.         
  578.             SetWindowLong(theWnd, GWL_USERDATA, 0);
  579.  
  580.             // destroy the port association
  581.             DestroyPortAssociation((CGrafPtr)GetHWNDPort(theWnd));
  582.             
  583.             break;
  584.     }
  585.  
  586.     return(DefMDIChildProc(theWnd, theMessage, wParam, lParam));
  587. }
  588.  
  589.  
  590. //////////
  591. //
  592. // QTFrame_QuitFramework
  593. // Do any framework-specific shut-down.
  594. //
  595. //////////
  596.  
  597. void QTFrame_QuitFramework (void)
  598. {
  599.     // set our global flag to indicate we're shutting down
  600.     gShuttingDown = true;
  601.     
  602.     // do application-specific processing that must occur before movie windows are closed
  603.     QTApp_Stop(kStopAppPhase_BeforeDestroyWindows);
  604.     
  605.     // close all open movie windows; note that the user can cancel the shutting down
  606.     QTFrame_CloseMovieWindows();
  607.     
  608.     // close the frame window, if we're still shutting down
  609.     if (gShuttingDown)
  610.         SendMessage(ghWnd, WM_CLOSE, 0, 0L);
  611. }
  612.  
  613.  
  614. //////////
  615. //
  616. // QTFrame_OpenCommandLineMovies
  617. // Parse the command line when the application first starts up and
  618. // open as movie documents any files specified on the command line.
  619. //
  620. // Based on the routine ParseCmdLinePriv in GraphicImporter.c.
  621. //
  622. //////////
  623.  
  624. void QTFrame_OpenCommandLineMovies (LPSTR theCmdLine)
  625. {
  626. #pragma unused(theCmdLine)
  627.     LPSTR                myCmdLine;
  628.     FSSpec                myFSSpec;
  629.     SHFILEINFO            myFileInfo;
  630.     
  631.     // get the command line for the current process
  632.     myCmdLine = GetCommandLine();
  633.  
  634.     // parse the command line
  635.     if (*myCmdLine) {
  636.         LPSTR            myTempLine;
  637.         
  638.         // the string preceding any white space is the name of the module (that is, the application)
  639.         myTempLine = strchr(myCmdLine, ' ');
  640.         if (myTempLine) {
  641.             myCmdLine = myTempLine;                  // skip the name of the application
  642.             while (*myCmdLine == ' ')
  643.                 myCmdLine++;                        // skip spaces to end of string or to first command
  644.  
  645.             while (*myCmdLine != '\0') {
  646.                 char     myFileName[MAX_PATH];
  647.                 char     myTempName[MAX_PATH];
  648.                 char     myBuffName[MAX_PATH];
  649.                 int     myIndex;
  650.                 
  651.                 // read thru the remaining string to find file names
  652.                 for (myIndex = 0; *myCmdLine != '\0'; myIndex++, myCmdLine++) {
  653.                     // if we encounter a space character, it might be a filename delimiter or a space in the filename;
  654.                     // we'll try to open the filename we have so far to see whether it's a valid filename; if not, the
  655.                     // space must be part of the filename we're constructing
  656.                     if (*myCmdLine == ' ') {
  657.                         HANDLE                myFindFile;
  658.                         WIN32_FIND_DATA        myFile;
  659.                     
  660.                         myTempName[myIndex] = '\0';
  661.                         strcpy(myBuffName, myTempName);
  662.                         
  663.                         myFindFile = FindFirstFile(myBuffName, &myFile);
  664.                         if (myFindFile != INVALID_HANDLE_VALUE) {
  665.                             // we found a file having the specified name; close our file search and
  666.                             // break out of our character-gobbling loop (since we've got a valid filename)
  667.                             FindClose(myFindFile);
  668.                             break;
  669.                         }
  670.                     }
  671.                 
  672.                     // if we made it here, *myCmdLine is part of the filename (possibly a space)
  673.                     myFileName[myIndex] = myTempName[myIndex] = *myCmdLine;
  674.                 }
  675.                 
  676.                 if (*myCmdLine != '\0')
  677.                     myCmdLine++;
  678.                 
  679.                 // add a terminating NULL character
  680.                 myFileName[myIndex] = '\0';
  681.  
  682.                 // make sure the filename picks out a QuickTime movie
  683.                 SHGetFileInfo(myFileName, (DWORD)0, &myFileInfo, sizeof(myFileInfo), SHGFI_TYPENAME);
  684.                 if (strcmp(myFileInfo.szTypeName, gMovieType) != 0)
  685.                     continue;
  686.                 
  687.                 // make an FSSpec record
  688.                 NativePathNameToFSSpec(myFileName, &myFSSpec, 0L);
  689.  
  690.                 // open the file in a movie window
  691.                 QTFrame_OpenMovieInWindow(NULL, &myFSSpec);
  692.             }
  693.  
  694.         } else
  695.             myCmdLine += strlen(myCmdLine);           // point to NULL
  696.     }
  697. }
  698.  
  699.  
  700. //////////
  701. //
  702. // QTFrame_CreateMovieWindow
  703. // Create a new window to display the movie in.
  704. //
  705. //////////
  706.  
  707. WindowReference QTFrame_CreateMovieWindow (void)
  708. {
  709.     WindowReference            myWindow = NULL;
  710.  
  711.     gWeAreCreatingWindow = true;
  712.     
  713.     // create a new window to display the movie in
  714.     myWindow = CreateWindowEx(WS_EX_MDICHILD,
  715.                                gChildName,
  716.                                "",
  717.                                0,
  718.                                CW_USEDEFAULT,
  719.                                CW_USEDEFAULT,
  720.                                CW_USEDEFAULT,
  721.                                CW_USEDEFAULT,
  722.                                ghWndMDIClient, 
  723.                                NULL,
  724.                                ghInst,
  725.                                0);
  726.     
  727.     // CreateWindowEx sends a WM_CREATE message to the window being created;
  728.     // we'll call QTFrame_CreateWindowObject when processing that message
  729.     
  730.     gWeAreCreatingWindow = false;
  731.  
  732.     return(myWindow);
  733. }
  734.  
  735.  
  736. //////////
  737. //
  738. // QTFrame_DestroyMovieWindow
  739. // Close the specified movie window.
  740. //
  741. //////////
  742.  
  743. void QTFrame_DestroyMovieWindow (WindowReference theWindow)
  744. {
  745. #pragma unused(theWindow)
  746.  
  747.     HWND                myChild = NULL;
  748.     
  749.     // close the active child window
  750.     myChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
  751.     if (IsWindow(myChild))
  752.         SendMessage(myChild, WM_CLOSE, 0L, 0L);
  753. }
  754.  
  755.  
  756. //////////
  757. //
  758. // QTFrame_GetDisplayName
  759. // Given a full pathname, return the part that trails the rightmost path separator,
  760. // in long file name format (not in 8.3 format).
  761. //
  762. //////////
  763.  
  764. void QTFrame_GetDisplayName (char *thePathName, char *theDispName)
  765. {
  766.     SHFILEINFO            myFileInfo;
  767.     DWORD                myResult;
  768.     
  769.     myResult = SHGetFileInfo(thePathName, (DWORD)0, &myFileInfo, sizeof(myFileInfo), SHGFI_DISPLAYNAME);
  770.     if (myResult != 0) {
  771.         // SHGetFileInfo successful
  772.         strcpy(theDispName, myFileInfo.szDisplayName);
  773.     } else {
  774.         // SHGetFileInfo not successful, so find the basename ourselves
  775.         short    myLength = 0;
  776.         short    myIndex;
  777.  
  778.         // get the length of the pathname
  779.         myLength = strlen(thePathName);
  780.         
  781.         // find the position of the rightmost path separator in thePathName
  782.         if (strchr(thePathName, kWinFilePathSeparator) != NULL) {
  783.     
  784.             myIndex = myLength - 1;
  785.             while (thePathName[myIndex] != kWinFilePathSeparator)
  786.                 myIndex--;
  787.                 
  788.             // calculate the length of the basename
  789.             myLength = myLength - myIndex - 1;
  790.     
  791.         } else {
  792.             // there is no rightmost path separator in thePathName;
  793.             // set myIndex so that myIndex + 1 == 0, for the call to BlockMove below
  794.             myIndex = -1;
  795.         }
  796.         
  797.         // copy into theDispName the substring of thePathName from myIndex + 1 to the end
  798.         BlockMove(&thePathName[myIndex + 1], theDispName, myLength);
  799.         theDispName[myLength] = '\0';
  800.     }
  801. }
  802.  
  803.  
  804. //////////
  805. //
  806. // QTFrame_ShowAboutBox 
  807. // Display and manage the About dialog box.
  808. //
  809. //////////
  810.  
  811. void QTFrame_ShowAboutBox (void)
  812. {
  813.     DialogBox(ghInst, MAKEINTRESOURCE(IDD_ABOUT), ghWnd, (DLGPROC)QTFrame_DialogProcedure);
  814. }
  815.  
  816.  
  817. //////////
  818. //
  819. // QTFrame_ShowCautionAlert 
  820. // Display and manage a caution alert.
  821. //
  822. // Based on ShowUserMessage by Stephen Chernicoff, in his WiniEdit application
  823. // (as described in the book "From Mac to Windows" on CodeWarrior reference CD).
  824. //
  825. //////////
  826.  
  827. int QTFrame_ShowCautionAlert (HWND theWnd, UINT theID, UINT theIconStyle, UINT theButtonStyle, LPSTR theTitle, LPSTR theArgument)
  828. {
  829.     char            myTemplate[kAlertMessageMaxLength];
  830.     char            myText[kAlertMessageMaxLength];
  831.     UINT            myStyle;
  832.     int                myItem;
  833.     
  834.     // beep, to get the user's attention (just like CautionAlert on MacOS)
  835.     QTFrame_Beep();
  836.     
  837.     // load the message text template from a resource
  838.     LoadString(ghInst, theID, myTemplate, sizeof(myTemplate));
  839.     
  840.     // insert argument into the message text template, to get the message text
  841.     wsprintf(myText, myTemplate, theArgument);
  842.     
  843.     // set the dialog box style
  844.     myStyle = theIconStyle | theButtonStyle | MB_APPLMODAL | MB_SETFOREGROUND;
  845.  
  846.     // display the dialog box
  847.     myItem = MessageBox(theWnd, myText, theTitle, myStyle);
  848.     
  849.     return(myItem);
  850. }
  851.  
  852.  
  853. //////////
  854. //
  855. // QTFrame_DialogProcedure 
  856. // Dialog callback procedure.
  857. //
  858. //////////
  859.  
  860. static UINT APIENTRY QTFrame_DialogProcedure (HWND theDialog, UINT theMessage, WPARAM wParam, LPARAM lParam)
  861. {
  862.     BOOL    isHandled = false;
  863.  
  864.     switch (theMessage) {
  865.     
  866.         case WM_INITDIALOG: {
  867.             Point            myPoint;
  868.             long            myWidth;
  869.             long            myHeight;
  870.             RECT            myRect;
  871.             RECT            myDeskRect;
  872.             HWND            myWindow;
  873.             OPENFILENAME    *myOFNPtr = (OPENFILENAME *)lParam;
  874.             
  875.             myWindow = theDialog;
  876.                 
  877.             // check whether theDialog is the Open File common dialog box
  878.             
  879.             // we need to do this because, for the Open File dialog box, theDialog isn't
  880.             // the actual visible dialog box, but an invisible child of the visible dialog box;
  881.             // for WM_INITDIALOG, lParam is the address of the structure passed to GetOpenFileName,
  882.             // so we can just look for the value we previously put into the lCustData field
  883.             // to make sure that we've got the correct dialog.
  884.             if (myOFNPtr != NULL)
  885.                 if (myOFNPtr->lCustData == kOpenDialogCustomData)
  886.                     myWindow = GetParent(theDialog);
  887.                 
  888.             // center the dialog window on the screen
  889.             GetWindowRect(myWindow, &myRect);
  890.             myWidth = myRect.right - myRect.left;
  891.             myHeight = myRect.bottom - myRect.top;
  892.             GetWindowRect(GetDesktopWindow(), &myDeskRect);
  893.             myPoint.h = (short)((myDeskRect.right + myDeskRect.left)/2 - myWidth/2);
  894.             myPoint.v = (short)((myDeskRect.top + myDeskRect.bottom)/3 - myHeight/3);
  895.             SetWindowPos(myWindow, 0, myPoint.h, myPoint.v, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  896.             
  897.             // let Windows set the input focus
  898.             isHandled = true;
  899.             break;
  900.         }
  901.         
  902.         case WM_CLOSE:
  903.             EndDialog(theDialog, IDOK);
  904.             isHandled = true;
  905.             break;
  906.         
  907.         case WM_COMMAND:
  908.             switch (LOWORD(wParam)) {
  909.                 case IDOK:
  910.                     EndDialog(theDialog, IDOK);
  911.                     isHandled = true;
  912.                     break;
  913.                 default:
  914.                     isHandled = false;
  915.                     break;
  916.             }
  917.             break;
  918.         
  919.         default:
  920.             isHandled = false;
  921.             break;
  922.     }
  923.  
  924.     return(isHandled);
  925. }
  926.  
  927.  
  928. //////////
  929. //
  930. // QTFrame_CalcWindowMinMaxInfo 
  931. // Get minimum and maximum possible size of this window.
  932. //
  933. //////////
  934.  
  935. static void QTFrame_CalcWindowMinMaxInfo (HWND theWnd, LPMINMAXINFO lpMinMax)
  936. {
  937.     WindowObject                myWindowObject = NULL;
  938.     Movie                        myMovie = NULL;
  939.     MovieController                myMC = NULL;
  940.     GraphicsImportComponent        myImporter = NULL;
  941.     Rect                        myRect;
  942.     ComponentResult                myErr = noErr;
  943.     
  944.     myWindowObject = QTFrame_GetWindowObjectFromWindow(theWnd);
  945.     if (myWindowObject != NULL) {
  946.         myMC = (**myWindowObject).fController;
  947.         myMovie = (**myWindowObject).fMovie;
  948.         myImporter = (**myWindowObject).fGraphicsImporter;
  949.     }
  950.     
  951.     // we're expecting a window with either an image or a movie
  952.     if ((myImporter == NULL) && (myMovie == NULL))
  953.         return;
  954.  
  955.     if (myImporter != NULL) {
  956.         // this window contains an image; we currently don't allow images to be resized,
  957.         // so we return both min and max rectangles set to the current image size, plus
  958.         // the appropriate window frame and caption sizes
  959.         myErr = GraphicsImportGetBoundsRect(myImporter, &myRect);
  960.         if (myErr == noErr) {
  961.             lpMinMax->ptMinTrackSize.x = myRect.right + (2 * GetSystemMetrics(SM_CXFRAME));
  962.             lpMinMax->ptMinTrackSize.y = myRect.bottom + (2 * GetSystemMetrics(SM_CXFRAME)) + GetSystemMetrics(SM_CYCAPTION);                                // caption height
  963.         
  964.             lpMinMax->ptMaxTrackSize.x = lpMinMax->ptMinTrackSize.x;
  965.             lpMinMax->ptMaxTrackSize.y = lpMinMax->ptMinTrackSize.y;
  966.             
  967.             lpMinMax->ptMaxSize.x = lpMinMax->ptMinTrackSize.x;
  968.             lpMinMax->ptMaxSize.y = lpMinMax->ptMinTrackSize.y;
  969.         }
  970.     }
  971.     
  972.     if (myMovie != NULL) {
  973.         // this window contains a movie; we currently don't allow movies to be resized
  974.         // except using the grow box in the movie controller bar; so set the min and max
  975.         // tracking rectangles to be the current size of the movie window
  976.         GetMovieBox(myMovie, &myRect);
  977.         if (myMC != NULL)
  978.             if (MCGetVisible(myMC))
  979.                 MCGetControllerBoundsRect(myMC, &myRect);
  980.                 
  981.         lpMinMax->ptMinTrackSize.x = myRect.right + (2 * GetSystemMetrics(SM_CXFRAME));
  982.         lpMinMax->ptMinTrackSize.y = myRect.bottom + (2 * GetSystemMetrics(SM_CXFRAME)) + GetSystemMetrics(SM_CYCAPTION) - 1;                                // caption height
  983.     
  984.         lpMinMax->ptMaxTrackSize.x = lpMinMax->ptMinTrackSize.x;
  985.         lpMinMax->ptMaxTrackSize.y = lpMinMax->ptMinTrackSize.y;
  986.         
  987.         lpMinMax->ptMaxSize.x = lpMinMax->ptMinTrackSize.x;
  988.         lpMinMax->ptMaxSize.y = lpMinMax->ptMinTrackSize.y;
  989.     }
  990. }
  991.  
  992.  
  993.